<?php

namespace App\Servers\WebSocket\Utils;

use Dotenv\Dotenv;

class JWT
{

    /**
     * 生成 JWT Token
     *
     * @param array $payload 自定义参数参数, 可选参数：exp 过期时间
     * @param string $alg  算法
     * @return String  JWT生成的token字符串,格式为<header>.<payload>.<signature>
     */
    public static function encode($payload = [], $alg = 'sha256'): String
    {
        $header = [
            'alg' => $alg,
            'typ' => 'JWT'
        ];

          // Payload
        $payload['iat'] = time();
        $payload['exp'] = isset($payload['exp']) ? $payload['exp'] : time() + 3600; // 1小时过期

        // Base64Url 编码
        $base64UrlHeader = self::base64UrlEncode(json_encode($header));
        $base64UrlPayload = self::base64UrlEncode(json_encode($payload));

        $dotenv = Dotenv::createImmutable(base_path());
        $dotenv->load();
        $secret = $_ENV['APP_KEY'];

        $signature = hash_hmac($header['alg'], $base64UrlHeader . '.' . $base64UrlPayload, $secret, true);;
        $base64UrlSignature = self::base64UrlEncode($signature);

        return $base64UrlHeader . '.' . $base64UrlPayload . '.' . $base64UrlSignature;
    }

    /**
     * 判断令牌是否可用
     *
     * @param [type] $token JWT令牌
     * @return boolean `true`:如果令牌可用，`false` 令牌不可用
     */
    public static function isExpire($token):bool {
        if ($token === null) {
            return false;
        }
        $decode = self::decode($token);
        if ($decode && $decode['exp'] > time()) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * Base64Url 编码
     */
    private static function base64UrlEncode(string $data): string
    {
        return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($data));
    }

    /**
     * 验证并解码 JWT Token
     */
    public static function decode(string $token): ?array {
        if ($token === null) {
            return null;
        }
        $parts = explode('.', $token);
        if (count($parts) !== 3) {
            return null;
        }
        
        list($base64UrlHeader, $base64UrlPayload, $base64UrlSignature) = $parts;
        $dotenv = Dotenv::createImmutable(base_path());
        $dotenv->load();
        $secret = $_ENV['APP_KEY'];

        // 解码 header
        $header = json_decode(self::base64UrlDecode($base64UrlHeader), true);
        
        // 验证签名
        $signature = self::base64UrlDecode($base64UrlSignature);
        $expectedSignature = hash_hmac($header['alg'], $base64UrlHeader . '.' . $base64UrlPayload, $secret, true);
        
        if (!hash_equals($signature, $expectedSignature)) {
            return null;
        }
        
        // 解码 payload
        $payload = json_decode(self::base64UrlDecode($base64UrlPayload), true);

        return $payload;
    }

    /**
     * Base64Url 解码
     */
    private static function base64UrlDecode(string $data): string {
        $padding = strlen($data) % 4;
        if ($padding) {
            $data .= str_repeat('=', 4 - $padding);
        }
        return base64_decode(str_replace(['-', '_'], ['+', '/'], $data));
    }
}


